﻿
Imports System.Threading
Imports std

Partial Public Class callbackManager
    Implements icallbackManager
    Public Shared ReadOnly [global] As callbackManager = Nothing

    Shared Sub New()
        CALLBACKMANAGER_CHECK_QUEUE_LENGTH =
            counter.registerAverageAndLastAverage("CALLBACKMANAGER_CHECK_QUEUE_LENGTH")
        CALLBACKMANAGER_CHECK_QUEUE_TICKS =
            counter.registerAverageAndLastAverage("CALLBACKMANAGER_CHECK_QUEUE_TICKS")
        CALLBACKMANAGER_CHECK_QUEUE_INTERVAL_TICKS =
            counter.registerAverageAndLastAverage("CALLBACKMANAGER_CHECK_QUEUE_INTERVAL_TICKS")
        CALLBACKMANAGER_CHECK_QUEUE_UNCHANGED_CYCLE =
            counter.registerAverageAndLastAverage("CALLBACKMANAGER_CHECK_QUEUE_UNCHANGED_CYCLE")

        [global] = New callbackManager()
    End Sub

    Public Shared Sub register(ByVal resolver As resolver)
        resolver.register(Of icallbackManager)([global])
    End Sub

    Public Shared Sub register()
        register(resolver.global)
    End Sub

    Public Shared Function currentCallbackAction() As callbackAction
        Return callbackAction.current()
    End Function

    Private Sub action_end(ByVal action As callbackAction)
        assert(Not action Is Nothing)
        action.action_end()
        assert(action.finished())
        trigger_check()
    End Sub

    Private Sub work(ByVal action As callbackAction)
        If action.begining() Then
            action.manager() = Me
            action.action_begin()
            If action.pending() Then
                begin_check(action)
            ElseIf action.ending() Then
                'only here when begin failed
                action_end(action)
            Else
                assert(False, "should cover all situations.")
            End If
        ElseIf action.ending() Then
            action_end(action)
        ElseIf action.finished() Then
            'insert a predefined finished callbackAction will trigger a check,
            'since in some cases, no further action is needed, such as readstream3
            trigger_check()
        Else
            assert(False, "should cover all situations.")
        End If
    End Sub

    Private Sub work(ByVal obj As Object)
        work(convertor.cast(Of callbackAction)(obj))
    End Sub

    Private Shared Function action_not_valid(ByVal action As callbackAction) As Boolean
        Return action Is Nothing OrElse action.pending()
    End Function

    Private Shared Function current_pending_timeout() As Boolean
        Return Not callbackAction.getCurrent() Is Nothing AndAlso
               callbackAction.getCurrent().pending() AndAlso
               callbackAction.getCurrent().timeout()
    End Function

    Public Function begin(ByVal action As callbackAction) As Boolean Implements icallbackManager.begin
        Dim tp As ithreadpool = Nothing
        tp = resolve(Of ithreadpool)()
        If action_not_valid(action) OrElse
           current_pending_timeout() Then
            Return False
        Else
            tp.insertJob(AddressOf work, action)
            Return True
        End If
    End Function

    Public Sub New()
        q = New list(Of callbackAction)()
        are = New AutoResetEvent(False)
        checkThread = startThread(AddressOf check_queue)
        checkThread.Name = "CALLBACKMANAGER_CHECK_QUEUE"
        checkThread.IsBackground() = True
    End Sub

    'avoid cloneable
    Public Function Clone() As Object Implements ICloneable.Clone
        Return Me
    End Function
End Class

Partial Public Class callbackManager
    Private Shared Function perftest_fake_action() As callbackAction
        Return New callbackAction(Function() As Boolean
                                      fake_work(5000)
                                      Return True
                                  End Function,
                                  Function() As Boolean
                                      fake_work(1000)
                                      Return rnd(0, 1) < 0.5
                                  End Function,
                                  Function() As Boolean
                                      fake_work(5000)
                                      Return True
                                  End Function)
    End Function

    Public Shared Sub perftest()
        assert(object_compare(resolve(Of threadpool)(), resolve(Of ithreadpool)()) = 0)
        registerConsoleExtHandle()
        While Not consoleExtSignal()
            If resolve(Of threadpool)().queueLength() + resolve(Of callbackManager).check_queue_length() < 32 Then
                resolve(Of callbackManager)().begin(perftest_fake_action())
            Else
                sleep(0)
            End If
        End While
        While resolve(Of callbackManager).check_queue_length() + resolve(Of threadpool)().queueLength() > 0
            sleep(0)
        End While
        resolve(Of threadpool)().stop()
        consoleExtHandleFinish()
    End Sub
End Class

Public Module callbackManager_Tests
    Public Sub perftest()
        threadpool.register()
        callbackManager.register()
        callbackManager.perftest()
    End Sub
End Module
